Skip to content

exzentcg.com Homelab Infrastructure Proposal

Project: Self-Hosted Business Application Platform Domain: exzentcg.com Infrastructure: Proxmox Homelab — 192.168.0.200 Prepared: April 2026


Executive Summary

This document proposes a secure, incrementally deployable homelab architecture to host business applications under the exzentcg.com domain. The design prioritises simplicity without sacrificing meaningful security — using Cloudflare's free-tier Zero Trust and Tunnel products as the external security boundary, and Proxmox's built-in Datacenter Firewall for internal network micro-segmentation.

The architecture is structured in two phases. Phase 1 delivers a production-ready n8n automation platform accessible at n8n.exzentcg.com. Phase 2 expands the platform to host additional business applications as the need arises, reusing all infrastructure built in Phase 1.

No additional hardware is required. No physical firewall appliances or router reconfigurations are needed. No inbound ports are opened on the home router at any point.


Network Diagram

graph TB
    users["Users / Customers"]
    external["External Services"]

    subgraph CF["Cloudflare Edge"]
        dns["DNS"] --> waf["WAF + DDoS"] --> zta["Zero Trust Access"] --> tunnel_cf["Tunnel"]
    end

    subgraph HOME["Home LAN .0.0/24"]
        router["Router .0.1"]

        subgraph PVE["Proxmox .0.200 — Firewall"]
            subgraph EDGE["edge-gateway .0.51"]
                cloudflared["cloudflared"]
                npm["Nginx Proxy Manager"]
            end

            subgraph N8N["n8n-app .0.52"]
                n8n_svc["n8n :5678"]
            end

            subgraph BIZ["biz-app .0.53 — Phase 2"]
                biz_svc["App :PORT"]
            end
        end
    end

    desktop["Desktop .0.16 — Admin"]
    apis["Internet APIs"]

    users --> dns
    external --> dns
    tunnel_cf -->|Encrypted Tunnel| cloudflared
    cloudflared --> npm
    npm -->|:5678| n8n_svc
    npm -.->|Phase 2| biz_svc
    router ---|DNS| EDGE
    router ---|DNS| N8N
    n8n_svc -->|:443 outbound| apis
    desktop -->|:8006 + SSH| PVE

    style CF fill:#fff3e0,stroke:#ff9800
    style HOME fill:#e3f2fd,stroke:#1565c0
    style PVE fill:#fff8e1,stroke:#f9a825
    style EDGE fill:#e8f5e9,stroke:#43a047
    style N8N fill:#e8f5e9,stroke:#43a047
    style BIZ fill:#f3f3f3,stroke:#999,stroke-dasharray: 5 5

Lateral movement blocked: Proxmox firewall DROP rules prevent n8n-app and biz-app from reaching Desktop (.0.16), Router (.0.1), Proxmox Host (.0.200), or any other LAN device. See firewall rule tables below for details.


Goals and Constraints

Goals

  • Host n8n.exzentcg.com (workflow automation) accessible over the internet under a custom domain.
  • Prevent any compromised container from reaching the home LAN, personal desktop (192.168.0.16), or the Proxmox management interface (192.168.0.200:8006).
  • Maintain a simple, low-overhead setup with no dedicated firewall VM.
  • Build a repeatable pattern so future business apps can be added with minimal rework.

Constraints

  • Single physical host running Proxmox (192.168.0.200).
  • Home network is flat (192.168.0.0/24) — no VLAN separation.
  • No pfSense/OPNsense VM (complexity trade-off accepted for Phase 1).
  • All containers will live on vmbr0 (the existing Proxmox bridge).

Architecture Overview

The design employs a "Hard Shell, Controlled Interior" model:

  • Cloudflare acts as the external security boundary (DDoS, WAF, Zero Trust identity gate, DNS proxy).
  • Cloudflare Tunnel (cloudflared) provides an outbound-only encrypted pipe — no inbound ports are ever opened on the home router.
  • Nginx Proxy Manager (NPM) on a dedicated edge-gateway LXC acts as the single internal ingress point, forwarding subdomains to the correct app container. All Cloudflare Tunnel traffic terminates at NPM — never directly at app containers.
  • Proxmox Datacenter Firewall enforces micro-segmentation at the hypervisor level, preventing lateral movement from any app container to the home LAN.
  • Tailscale provides remote admin access to the Proxmox host, independent of Cloudflare. The admin laptop's Tailscale IP is added to the admin_desktop IP set so the same firewall rules apply whether admin is on-LAN or remote. This is deliberate: a Cloudflare outage must not lock the operator out of the hypervisor.

The key security principle: even if n8n is fully compromised, the attacker is isolated inside the n8n-app container with no path to your desktop, router, or Proxmox host.


IP and Component Layout

All LXCs reside on vmbr0 within the existing 192.168.0.0/24 subnet. Static IPs should be assigned via Proxmox container network config (or DHCP reservation on the router).

Component IP Address Role
Home Router 192.168.0.1 Default gateway, DNS forwarder
Proxmox Host 192.168.0.200 Hypervisor — management only
Desktop (Admin) 192.168.0.16 Only trusted admin machine
LXC: edge-gateway 192.168.0.51 cloudflared + Nginx Proxy Manager
LXC: n8n-app 192.168.0.52 n8n automation platform (Phase 1)
LXC: biz-app 192.168.0.53 Business app — ERPNext or similar (Phase 2)

Phase 1: n8n Deployment

Step 1 — Create LXC: edge-gateway (192.168.0.51)

This is the single container that faces the internet via Cloudflare. It runs two services, both deployed as a single Docker Compose stack under /opt/edge-gateway/:

  • cloudflared: Maintains an outbound TLS tunnel to Cloudflare's edge. Cloudflare routes n8n.exzentcg.com traffic into this tunnel. Runs with network_mode: host so it can reach NPM's localhost bind.
  • Nginx Proxy Manager (NPM): Receives HTTP/S traffic from cloudflared and proxies it to the correct internal container IP and port. Binds only to 127.0.0.1:80/443 (cloudflared path) and 192.168.0.51:81 (admin panel) — never to 0.0.0.0, providing a second layer of defence behind the Proxmox firewall.

Single compose file = single backup target (/opt/edge-gateway/) containing the compose file, NPM data, Let's Encrypt certs, and the tunnel token in .env.

Recommended LXC specs: Debian 12, 1 vCPU, 1 GB RAM, 4 GB disk. (RAM bumped from the original 512 MB to accommodate cloudflared now running as a Docker container alongside NPM rather than as a native apt package.)

Tunnel ingress rule (configured in Cloudflare dashboard):

n8n.exzentcg.com  →  http://192.168.0.51:80

Important: The tunnel target is NPM on the edge-gateway (192.168.0.51:80), not the n8n container directly. NPM then proxies to 192.168.0.52:5678. This keeps NPM as the single internal routing point for all subdomains — consistent for Phase 1 and Phase 2.

NPM proxy host configuration:

Source:       n8n.exzentcg.com
Forward to:   http://192.168.0.52:5678

Step 2 — Create LXC: n8n-app (192.168.0.52)

This container runs n8n as a Docker Compose service under /opt/n8n/, matching the edge-gateway pattern.

Recommended LXC specs: Debian 12, 2 vCPU, 2 GB RAM, 10 GB disk.

n8n binds to 192.168.0.52:5678 (the LXC's LAN IP), not 0.0.0.0. Proxmox firewall rules additionally ensure only edge-gateway can reach this port.

Required n8n environment variables:

N8N_HOST=n8n.exzentcg.com
N8N_PORT=5678
N8N_PROTOCOL=https
WEBHOOK_URL=https://n8n.exzentcg.com
NODES_EXCLUDE=["n8n-nodes-base.executeCommand"]
N8N_ENCRYPTION_KEY=<generated once, stored in .env and password manager>
GENERIC_TIMEZONE=Asia/Singapore
TZ=Asia/Singapore

Image pinning: n8nio/n8n:<version> (not :latest). Upgrades happen deliberately on the weekly maintenance window, not via auto-pull.

Security note — Execute Command node: n8n's Execute Command node (CVE CVSS 9.9) allows authenticated users to run arbitrary OS commands on the host. Disabling it via NODES_EXCLUDE eliminates this attack vector entirely.

Critical — N8N_ENCRYPTION_KEY: n8n encrypts every stored credential (API keys, OAuth tokens, DB passwords) with this key. It is generated once with openssl rand -hex 32 before n8n is first started, and stored in both /opt/n8n/.env (chmod 600) and a password manager. Losing this key is equivalent to losing every credential n8n holds — it must be backed up separately from the n8n data volume.

Step 3 — Cloudflare Zero Trust Access Policy

For a non-public admin tool like n8n, an access policy is mandatory.

In Cloudflare: Zero Trust > Access > Applications:

  1. Add application for n8n.exzentcg.com.
  2. Session duration: 24 hours.
  3. Policy rule: Allow where Emails equals [your email].
  4. Authentication method: One-time PIN (email) or connect an identity provider (Google, GitHub).

This means any browser hitting n8n.exzentcg.com is challenged by Cloudflare before the tunnel even forwards the request. The n8n login screen is a secondary layer behind this.

For webhook endpoints (Stripe, Telegram, etc.): Create a separate bypass policy for the path /webhook/* so external services can POST without the identity gate. The main UI paths (/, /workflows, /credentials) remain protected.


Proxmox Firewall Configuration

The firewall is configured at three levels: Datacenter > Node > LXC. All three must be enabled for rules to take effect.

⚠️ Critical: Rule ordering. Proxmox evaluates firewall rules top-to-bottom, first match wins. In every rule set below, DROP rules for lan_subnet must be placed above any ALLOW-to-any rules. If the ALLOW-to-any on port 443 is evaluated first, traffic destined for a LAN IP on port 443 will be permitted — defeating lateral movement prevention. Always verify rule order after editing.

Pre-requisite: Lockout Prevention

Before enabling the Datacenter-level firewall, create these rules on the Node (pve) firewall — failure to do this will lock you out of the Proxmox WebUI:

# Direction Action Source Port Protocol Comment
1 IN ACCEPT 192.168.0.16 8006 TCP Admin WebUI access
2 IN ACCEPT 192.168.0.16 22 TCP Admin SSH access
3 IN DROP any 8006 TCP Block all others from WebUI

Proxmox Host: Datacenter IP Sets

Define reusable IP sets in Datacenter > Firewall > IPSet:

IP Set Name Value Purpose
admin_desktop 192.168.0.16, <laptop_tailscale_ip> Trusted admin machines (LAN desktop + Tailscale laptop)
lan_subnet 192.168.0.0/24 Entire home LAN
router_gw 192.168.0.1 Default gateway / DNS
edge_gw 192.168.0.51 edge-gateway LXC

LXC: edge-gateway Firewall Rules

# Direction Action Source/Dest Port Protocol Comment
1 IN ACCEPT 127.0.0.1 80, 443 TCP cloudflared (local) → NPM
2 IN ACCEPT admin_desktop 81 TCP NPM admin panel from desktop only
3 IN DROP any any any Block all other inbound
4 OUT ACCEPT router_gw 53 UDP/TCP DNS resolution
5 OUT ACCEPT 192.168.0.52 5678 TCP Proxy to n8n-app
6 OUT ACCEPT 192.168.0.53 any TCP Proxy to biz-app (Phase 2)
7 OUT DROP lan_subnet any any Block all other LAN access
8 OUT ACCEPT any 443 TCP cloudflared tunnel + Cloudflare API
9 OUT ACCEPT any 80 TCP HTTP fallback (package updates)

Change from previous version: Inbound rule #1 is now scoped to 127.0.0.1 (localhost) because cloudflared runs on the same container and connects to NPM locally. This prevents any other LAN device from reaching NPM's HTTP ports. Rule #2 allows desktop-only access to NPM's admin panel (port 81).

LXC: n8n-app Firewall Rules

# Direction Action Source/Dest Port Protocol Comment
1 IN ACCEPT edge_gw 5678 TCP Only proxy may reach n8n
2 IN ACCEPT admin_desktop 22 TCP SSH from admin desktop
3 IN DROP any any any Block all other inbound
4 OUT ACCEPT router_gw 53 UDP/TCP DNS resolution
5 OUT DROP lan_subnet any any Lateral movement prevention
6 OUT ACCEPT any 443 TCP n8n calling external APIs (HTTPS)

Changes from previous version:

  • Outbound port 80 removed. Modern APIs are HTTPS-only. If a specific integration requires HTTP, add it as a targeted rule for that destination only.
  • Rule #5 (DROP lan_subnet) is ordered above rule #6 (ALLOW any:443). This is critical — it ensures traffic to 192.168.0.x:443 is dropped before the allow-to-any rule can match it. This closes the DNS rebinding edge case where a malicious domain resolves to a LAN IP.
  • SSH access added from admin desktop (rule #2) for maintenance.

Traffic Flow Summary

External User Visiting n8n.exzentcg.com

User Browser
    → Cloudflare DNS resolves to Cloudflare IP (home IP never exposed)
    → Cloudflare WAF + DDoS scrubbing
    → Cloudflare Zero Trust: identity challenge (email PIN / OAuth)
    → Cloudflare Tunnel: encrypted outbound tunnel to edge-gateway LXC
    → cloudflared (192.168.0.51) forwards to localhost NPM
    → Nginx Proxy Manager: routes n8n.exzentcg.com to 192.168.0.52:5678
    → n8n application
    → Response follows same path in reverse

n8n Calling an External API (e.g., Google Sheets)

n8n-app (192.168.0.52)
    → Proxmox firewall: DROP lan_subnet check — destination is not LAN, skip
    → Proxmox firewall: ALLOW outbound 443 to internet
    → Router (192.168.0.1)
    → Internet → Google API
    → Response returns to n8n-app

n8n Attempting to Reach Desktop (Attack Scenario)

Compromised n8n-app (192.168.0.52)
    → Attempts connection to 192.168.0.16 (any port, including 443)
    → Proxmox firewall: rule #5 DROP (lan_subnet) matched BEFORE rule #6 (allow any:443)
    → Connection never established ✓

DNS Rebinding Attack Scenario

Compromised n8n-app (192.168.0.52)
    → Resolves attacker-controlled domain to 192.168.0.16
    → Attempts HTTPS connection to 192.168.0.16:443 via the malicious domain
    → Proxmox firewall: rule #5 DROP (lan_subnet) matches destination IP regardless of DNS name
    → Connection never established ✓

Phase 2: Adding Business Applications

When ready to add a business app (e.g., ERPNext, custom web app), the process follows the established pattern:

  1. Create LXC: biz-app (192.168.0.53) with the same firewall template as n8n-app (adjust inbound port for the app).
  2. Add NPM proxy host on edge-gateway: app.exzentcg.com → http://192.168.0.53:PORT.
  3. Add Cloudflare Tunnel ingress rule: app.exzentcg.com → http://192.168.0.51:80 (always through NPM — this is the standard).
  4. Add Cloudflare Access policy for app.exzentcg.com (public or employee-only, as required).
  5. Add edge-gateway firewall rule: OUT ACCEPT 192.168.0.53:<PORT> (insert before the lan_subnet DROP rule).
  6. If a database container is needed: create a DB LXC (192.168.0.54), allow inbound connections only from 192.168.0.53 on the DB port, block all other LAN and internet access.

Standard: All Cloudflare Tunnel ingress rules must target NPM on 192.168.0.51:80. Never point a tunnel directly at an app container. NPM is the single internal routing point.

No changes to existing Phase 1 infrastructure are required.


Security Assessment

Threat Mitigated By Residual Risk
Internet port scanning Cloudflare Tunnel — no open ports None
DDoS / volumetric attack Cloudflare WAF + DDoS protection Low
Unauthorised n8n access Cloudflare Zero Trust Access Low
n8n command execution CVE NODES_EXCLUDE env var None (node disabled)
Compromised n8n → LAN pivot Proxmox per-LXC firewall DROP rules (ordered above ALLOW) Low
DNS rebinding to LAN IPs DROP lan_subnet evaluated before ALLOW any:443 Low
Brute-force n8n login Zero Trust gate before login screen Low
Home IP exposure Cloudflare proxy (orange cloud DNS) None
Proxmox GUI exposure Node firewall ALLOW only from admin_desktop IP set (LAN desktop + Tailscale laptop) Low
NPM admin panel exposure Inbound restricted to localhost + admin desktop Low
Remote admin dependency on Cloudflare Tailscale mesh is independent of Cloudflare; outage of one does not lock out the other None

Accepted risk: No network-layer IDS/IPS is present (this would require OPNsense in Phase 2+). Application-layer security relies on keeping n8n and its dependencies updated.


Maintenance Checklist

  • Weekly: Check n8n for available updates; apply in a maintenance window.
  • Weekly: Review Cloudflare Access logs for unexpected login attempts.
  • Monthly: Review Proxmox firewall logs for anomalous DROP hits.
  • Monthly: Snapshot both LXCs in Proxmox before any major changes.
  • Monthly: Verify firewall rule ordering has not changed after any Proxmox updates.
  • As needed: Rotate n8n credentials and API keys stored in n8n's credential vault.

Future Considerations (Phase 3+)

Once multiple business applications are running, migrating from a flat Proxmox Firewall model to an OPNsense virtual firewall with proper VLAN/DMZ segmentation is strongly recommended. OPNsense running as a Proxmox VM provides Suricata-based intrusion detection, centralised firewall management, and a cleaner separation between the home LAN and business workloads — without requiring any additional physical hardware.